/*********************************************************************************************************
*
* File                : ws_W25Qx.c
* Hardware Environment: 
* Build Environment   : RealView MDK-ARM  Version: 4.20
* Version             : V1.0
* By                  : 
*
*                                  (c) Copyright 2005-2011, WaveShare
*                                       http://www.waveshare.net
*                                          All Rights Reserved
*
*********************************************************************************************************/

#include "W25QXX.h"

//SPI 
//TxData:
//:
uint8_t SPI1_ReadWriteByte(uint8_t TxData)
{
    uint8_t Rxdata;
    HAL_SPI_TransmitReceive(&hspi2, &TxData, &Rxdata, 1, 1000);       
    return Rxdata;                      //       
}
uint16_t W25QXX_TYPE;                   //W25QXX
uint16_t W25QXX_ReadID(void)
{
    uint16_t Temp = 0;    
    /*  */
    W25Qx_Enable();               
    SPI1_ReadWriteByte(0x90);//ID     
    SPI1_ReadWriteByte(0x00);       
    SPI1_ReadWriteByte(0x00);       
    SPI1_ReadWriteByte(0x00);                  
    Temp|=SPI1_ReadWriteByte(0xFF)<<8;  
    Temp|=SPI1_ReadWriteByte(0xFF);  
    W25QXX_TYPE=Temp;
    /*  */
    W25Qx_Disable();                 
    return Temp;
} 
uint8_t W25QXX_ReadSR(uint8_t regno)   
{  
    uint8_t byte=0,command=0; 
    switch(regno)
    {
        case 1:
            command=W25X_ReadStatusReg1;    //1
            break;
    }    
    /*  */
     W25Qx_Enable();  
    SPI1_ReadWriteByte(command);            //    
    byte=SPI1_ReadWriteByte(0Xff);          //  
    /*  */
     W25Qx_Disable();  
    return byte;   
} 
void W25QXX_Wait_Busy(void)   
{   
    while((W25QXX_ReadSR(1)&0x01)==0x01);   // BUSY
}
void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)   
{ 
    uint16_t i;                             
    /*  */
    W25Qx_Enable();  
    SPI1_ReadWriteByte(W25X_ReadData);      //  
    SPI1_ReadWriteByte((uint8_t)((ReadAddr)>>16));   //24bit    
    SPI1_ReadWriteByte((uint8_t)((ReadAddr)>>8));   
    SPI1_ReadWriteByte((uint8_t)ReadAddr);   
    for(i=0;i<NumByteToRead;i++)
    { 
        pBuffer[i]=SPI1_ReadWriteByte(0XFF);    //  
    }
    /*  */
    W25Qx_Disable();                               
}

//W25QXX 
//WEL   
void W25QXX_Write_Enable(void)   
{
     W25Qx_Enable();                           //   
    SPI1_ReadWriteByte(W25X_WriteEnable);   //  
    W25Qx_Disable();                    //              
} 
//
//Dst_Addr: 
//:150ms
void W25QXX_Erase_Sector(uint32_t Dst_Addr)   
{  
    //falsh,   
    //printf("fe:%x\r\n",Dst_Addr);   
    Dst_Addr*=4096;
    W25QXX_Write_Enable();                  //SET WEL    
    W25QXX_Wait_Busy();   
    /*  */
    W25Qx_Enable();     
    SPI1_ReadWriteByte(W25X_SectorErase);   // 
    SPI1_ReadWriteByte((uint8_t)((Dst_Addr)>>16));  //24bit    
    SPI1_ReadWriteByte((uint8_t)((Dst_Addr)>>8));   
    SPI1_ReadWriteByte((uint8_t)Dst_Addr);  
    /*  */
    W25Qx_Disable();             
    W25QXX_Wait_Busy();                     //
} 
//W25QXX 
//WEL  
void W25QXX_Write_Disable(void)   
{  
     W25Qx_Enable();                        //   
    SPI1_ReadWriteByte(W25X_WriteDisable);  //    
    W25Qx_Disable();                               //              
} 

//SPI(0~65535)256
//256
//pBuffer:
//WriteAddr:(24bit)
//NumByteToWrite:(256),!!!   
void W25QXX_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
    uint16_t i;  
    W25QXX_Write_Enable();                  //SET WEL 
    /*  */
    W25Qx_Enable();  
    SPI1_ReadWriteByte(W25X_PageProgram);   //   
    SPI1_ReadWriteByte((uint8_t)((WriteAddr)>>16)); //24bit    
    SPI1_ReadWriteByte((uint8_t)((WriteAddr)>>8));   
    SPI1_ReadWriteByte((uint8_t)WriteAddr);   
    for(i=0;i<NumByteToWrite;i++)SPI1_ReadWriteByte(pBuffer[i]);// 
    /*  */    
    W25Qx_Disable();      
    W25QXX_Wait_Busy();                    //
} 

//SPI FLASH 
//0XFF,0XFF!
// 
//,!
//pBuffer:
//WriteAddr:(24bit)
//NumByteToWrite:(65535)
//CHECK OK
void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
{                    
    uint16_t pageremain;       
    pageremain=256-WriteAddr%256; //                
    if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//256
    while(1)
    {      
        W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
        if(NumByteToWrite==pageremain)break;//
        else //NumByteToWrite>pageremain
        {
            pBuffer+=pageremain;
            WriteAddr+=pageremain;  

            NumByteToWrite-=pageremain;           //
            if(NumByteToWrite>256)pageremain=256; //256
            else pageremain=NumByteToWrite;       //256
        }
    };      
} 
//SPI FLASH  
//
//!
//pBuffer:
//WriteAddr:(24bit)                      
//NumByteToWrite:(65535)   
uint8_t W25QXX_BUFFER[4096];         
void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)   
{ 
    uint32_t secpos;
    uint16_t secoff;
    uint16_t secremain;    
    uint16_t i;    
    uint8_t * W25QXX_BUF;     
    W25QXX_BUF=W25QXX_BUFFER;        
    secpos=WriteAddr/4096;//  
    secoff=WriteAddr%4096;//
    secremain=4096-secoff;//   
    //printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//
    if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//4096
    while(1) 
    {   
        W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//
        for(i=0;i<secremain;i++)//
        {
            if(W25QXX_BUF[secoff+i]!=0XFF)break;//        
        }
        if(i<secremain)//
        {
            W25QXX_Erase_Sector(secpos);//
            for(i=0;i<secremain;i++)       //
            {
                W25QXX_BUF[i+secoff]=pBuffer[i];      
            }
            W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//  

        }else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//,.                  
        if(NumByteToWrite==secremain)break;//
        else//
        {
            secpos++;//1
            secoff=0;//0    

            pBuffer+=secremain;  //
            WriteAddr+=secremain;//       
            NumByteToWrite-=secremain;              //
            if(NumByteToWrite>4096)secremain=4096;  //
            else secremain=NumByteToWrite;          //
        }    
    };   
}
/**
  * @brief  Initializes the W25Q128FV interface.
  * @retval None
  */
uint8_t BSP_W25Qx_Init(void)
{ 
	/* Reset W25Qxxx */
	BSP_W25Qx_Reset();
	
	return W25QXX_ReadSR(1);
}

///**
//  * @brief  This function reset the W25Qx.
//  * @retval None
//  */
static void	BSP_W25Qx_Reset(void)
{
	uint8_t cmd[2] = {RESET_ENABLE_CMD,RESET_MEMORY_CMD};
	
	W25Qx_Enable();
	/* Send the reset command */
	HAL_SPI_Transmit(&hspi2, cmd, 2, W25Qx_TIMEOUT_VALUE);	
	W25Qx_Disable();

}



